#include "TcpConnection.h"

TcpConnection::TcpConnection( boost::asio::io_service& io_service) 
	: socket_(io_service), resolver_(io_service), remote_socket_(io_service)
{
}

TcpConnection::~TcpConnection(void)
{
}

tcp::socket& TcpConnection::socket()
{
	return socket_;
}

void TcpConnection::start()
{
	std::cout << "Peer IP: " << socket_.remote_endpoint().address().to_string() << std::endl;
	std::cout << "Peer Port: " << socket_.remote_endpoint().port() << std::endl;
	std::cout << "Local IP: " <<socket_.local_endpoint().address().to_string() << std::endl;
	std::cout << "Local Port: " <<socket_.local_endpoint().port() << std::endl;
	TcpConnection::i = 0;
	boost::asio::async_read_until(socket_, request_, "\r\n\r\n",
          boost::bind(&TcpConnection::client_handle_read_headers, shared_from_this(),
          boost::asio::placeholders::error));
}

void TcpConnection::client_handle_read_headers(const boost::system::error_code& err)
{
	if (!err)
	{
		std::cout << "start header " << TcpConnection::i << std::endl;
		TcpConnection::i ++;
		// Process the response headers.
		std::istream request_stream(&request_);

		/// create connection to remote web server
		std::ostream request_remote_stream(&remote_request_);

		//get each character to parse http request
		while (request_stream.good())          // loop while extraction from file is possible
		{
			char c = request_stream.get();       // get character from file
			if (request_stream.good())
			{
				std::cout << c;
				//push request to remote stream
				request_remote_stream << c;

				//parse http request
				boost::tribool result = request_parser_.consume(request_data_, c);
			}
				
		}

		// Write whatever content we already have to output.
		if (request_.size() > 0)
		{
			std::cout << &request_;
		}
		for( header headeri : request_data_.headers) 
		{
			if( headeri.name == "Host" ) request_data_.host = headeri.value;
		}
		
		///request_remote_stream << "GET " << request_data_.uri << " HTTP/1.0\r\n";
		///request_remote_stream << "Host: " << request_data_.host << "\r\n";
		///request_remote_stream << "Accept: */*\r\n";
		///request_remote_stream << "Connection: close\r\n\r\n";

		//std::cout << &remote_request_;

		// Start an asynchronous resolve to translate the server and service names
		// into a list of endpoints.
		tcp::resolver::query query(request_data_.host, "http");
		resolver_.async_resolve(query,
			boost::bind(&TcpConnection::handle_resolve, shared_from_this(),
			boost::asio::placeholders::error,
			boost::asio::placeholders::iterator));
	}
	else
	{
		std::cout << "Error: " << err << "\n";
	}
}

void TcpConnection::handle_resolve(const boost::system::error_code& err,
      tcp::resolver::iterator endpoint_iterator)
{
	if (!err)
	{
		// Attempt a connection to each endpoint in the list until we
		// successfully establish a connection.
		std::cout << "handle_resolve" << std::endl;
		boost::asio::async_connect(remote_socket_, endpoint_iterator,
			boost::bind(&TcpConnection::handle_connect, shared_from_this(),
			boost::asio::placeholders::error));
	}
	else
	{
		std::cout << "Error: " << err.message() << "\n";
	}
}

void TcpConnection::handle_connect(const boost::system::error_code& err)
{
	if (!err)
	{
		// The connection was successful. Send the request.
		std::cout << "handle_connect" << std::endl;
		boost::asio::async_write(remote_socket_, remote_request_,
			boost::bind(&TcpConnection::handle_write_request, shared_from_this(),
			boost::asio::placeholders::error));
	}
	else
	{
		std::cout << "Error: " << err.message() << "\n";
	}
}

void TcpConnection::handle_write_request(const boost::system::error_code& err)
{
	if (!err)
	{
		// Read the response status line. The response_ streambuf will
		// automatically grow to accommodate the entire line. The growth may be
		// limited by passing a maximum size to the streambuf constructor.
		std::cout << "handle_write_request" << std::endl;
		boost::asio::async_read_until(remote_socket_, remote_response_, "\r\n",
			boost::bind(&TcpConnection::handle_read_status_line, shared_from_this(),
			boost::asio::placeholders::error));
	}
	else
	{
		std::cout << "Error: " << err.message() << "\n";
	}
}

void TcpConnection::handle_read_status_line(const boost::system::error_code& err)
{
	if (!err)
	{
		std::cout << "handle_read_status_line" << std::endl;
		// Check that response is OK.
		std::istream response_stream(&remote_response_);
		std::string http_version;
		response_stream >> http_version;
		unsigned int status_code;
		response_stream >> status_code;
		std::string status_message;
		std::getline(response_stream, status_message);
		if (!response_stream || http_version.substr(0, 5) != "HTTP/")
		{
			std::cout << "Invalid response\n";
			return;
		}
		if (status_code != 200)
		{
			std::cout << "Response returned with status code ";
			std::cout << status_code << "\n";
			return;
		}

		// Read the response headers, which are terminated by a blank line.
		boost::asio::async_read_until(socket_, remote_response_, "\r\n\r\n",
			boost::bind(&TcpConnection::handle_read_headers, shared_from_this(),
			boost::asio::placeholders::error));
	}
	else
	{
		std::cout << "Error: " << err << "\n";
	}
}

void TcpConnection::handle_read_headers(const boost::system::error_code& err)
{
	if (!err)
	{
		std::cout << "handle_read_headers" << std::endl;
		// Process the response headers.
		std::istream response_stream(&remote_response_);
		std::string header;

		while (std::getline(response_stream, header) && header != "\r")
			std::cout << header << "\n";
		std::cout << "\n";

		// Write whatever content we already have to output.
		if (remote_response_.size() > 0)
			std::cout << &remote_response_;

		// Start reading remaining data until EOF.
		boost::asio::async_read(remote_socket_, remote_response_,
			boost::asio::transfer_at_least(1),
			boost::bind(&TcpConnection::handle_read_content, shared_from_this(),
			boost::asio::placeholders::error));
	}
	else
	{
		std::cout << "Error: " << err << "\n";
	}
}

void TcpConnection::handle_read_content(const boost::system::error_code& err)
{
	if (!err)
	{
		std::cout << "handle_read_content" << std::endl;
		// Write all of the data that has been read so far.
		std::cout << &response_;

		// Continue reading remaining data until EOF.
		boost::asio::async_read(remote_socket_, remote_response_,
			boost::asio::transfer_at_least(1),
			boost::bind(&TcpConnection::handle_read_content, shared_from_this(),
			boost::asio::placeholders::error));
	}
	else if (err != boost::asio::error::eof)
	{
		std::cout << "Error: " << err << "\n";
	}
}